#include <ctime>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <random>
#include <windows.h>
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,abm,mmx,avx,avx2")
#pragma GCC optimize("unroll-loops")
typedef unsigned long long u64_t;
typedef unsigned char u16_t;
const char skillNameMap[][13] = {
	"火球术", "冰冻术", "雷击术", "地裂术", "吸血攻击", "投毒", "连击",
	"会心一击", "瘟疫", "生命之轮", "狂暴术", "魅惑", "加速术", "减速术",
	"诅咒", "治愈魔法", "苏生术", "净化", "铁壁", "蓄力", "聚气",
	"潜行", "血祭", "分身", "幻术", "防御", "守护", "伤害反弹",
	"护身符", "护盾", "反击", "吞噬", "召唤亡灵", "垂死抗争", "隐匿",
	"啧", "啧", "啧", "啧", "啧"};
const int N = 256, M = 128, K = 64, skill_cnt = 40;
char team[N], tmp[N], prefix[N], fname[N], _tmp[N], tmq[N];
int V;
int prop[8];
char *cvt(const char *gb2312)
{
	int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
	wchar_t *wstr = new wchar_t[len + 1];
	memset(wstr, 0, len + 1);
	MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
	len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
	char *str = new char[len + 1];
	memset(str, 0, len + 1);
	WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
	if (wstr)
		delete[] wstr;
	return str;
}
char *dvt(char *p)
{
	DWORD dwNum = MultiByteToWideChar(CP_UTF8, 0, p, -1, NULL, 0);
	char *psText;
	wchar_t *pwText = (wchar_t *)malloc(dwNum * sizeof(wchar_t));
	dwNum = MultiByteToWideChar(CP_UTF8, 0, p, -1, pwText, dwNum);
	dwNum = WideCharToMultiByte(CP_ACP, 0, pwText, -1, NULL, 0, NULL, NULL);
	psText = (char *)malloc(dwNum * sizeof(char));
	dwNum = WideCharToMultiByte(CP_ACP, 0, pwText, -1, psText, dwNum, NULL, NULL);
	free(pwText);
	return psText;
}
struct Name
{
	u16_t val_base[N], val[N];
	u16_t name_base[M], freq[16], skill[skill_cnt], p, q;
	int q_len;
	inline u16_t m()
	{
		q += val[++p];
		std::swap(val[p], val[q]);
		return val[val[p] + val[q] & 255];
	}
	inline int gen()
	{
		int u = m();
		return (u << 8 | m()) % skill_cnt;
	}
	void load_team(const char *_team)
	{
		char *team = cvt(_team);
		int t_len = strlen(team) + 1;
		u16_t s;
		for (int i = 0; i < N; i++)
			val_base[i] = i;
		for (int i = s = 0; i < N; ++i)
		{
			if (i % t_len)
				s += team[i % t_len - 1];
			s += val_base[i];
			std::swap(val_base[i], val_base[s]);
		}
		delete[] team;
	}
	void load_name(const char *name)
	{
		q_len = -1;
		memcpy(val, val_base, sizeof val);
		u16_t s;
		for (int _ = 0; _ < 2; _++)
			for (int i = s = 0; i < N; i++)
			{
				s += name[i & 15];
				s += val[i];
				std::swap(val[i], val[s]);
			}
		for (int i = 0; i < 96; i += 8)
		{
			val[i + 0] = val[i + 0] * 181 + 160;
			val[i + 1] = val[i + 1] * 181 + 160;
			val[i + 2] = val[i + 2] * 181 + 160;
			val[i + 3] = val[i + 3] * 181 + 160;
			val[i + 4] = val[i + 4] * 181 + 160;
			val[i + 5] = val[i + 5] * 181 + 160;
			val[i + 6] = val[i + 6] * 181 + 160;
			val[i + 7] = val[i + 7] * 181 + 160;
		}
		for (int i = 0; i < 96 && q_len < 30; i++)
			if (val[i] >= 89 && val[i] < 217)
				name_base[++q_len] = val[i] & 63;
		if (q_len < 30)
		{
			for (int i = 96; i < N; i += 8)
			{
				val[i + 0] = val[i + 0] * 181 + 160;
				val[i + 1] = val[i + 1] * 181 + 160;
				val[i + 2] = val[i + 2] * 181 + 160;
				val[i + 3] = val[i + 3] * 181 + 160;
				val[i + 4] = val[i + 4] * 181 + 160;
				val[i + 5] = val[i + 5] * 181 + 160;
				val[i + 6] = val[i + 6] * 181 + 160;
				val[i + 7] = val[i + 7] * 181 + 160;
			}
			for (int i = 96; i < N && q_len < 30; i++)
				if (val[i] >= 89 && val[i] < 217)
					name_base[++q_len] = val[i] & 63;
		}
		V = 0;
#define median(x, y, z) std::max(std::min(x, y), std::min(std::max(x, y), z))
		V += median(name_base[10], name_base[11], name_base[12]);
		V += median(name_base[13], name_base[14], name_base[15]);
		V += median(name_base[16], name_base[17], name_base[18]);
		V += median(name_base[19], name_base[20], name_base[21]);
		V += median(name_base[22], name_base[23], name_base[24]);
		V += median(name_base[25], name_base[26], name_base[27]);
		V += median(name_base[28], name_base[29], name_base[30]);
		if (V < 307)
			return;
		std::sort(name_base, name_base + 10);
		prop[7] = 154 + name_base[3] + name_base[4] + name_base[5] + name_base[6];
		V += prop[7] / 3;
		if (V < 440)
			return;
		prop[0] = median(name_base[10], name_base[11], name_base[12]);
		prop[1] = median(name_base[13], name_base[14], name_base[15]);
		prop[2] = median(name_base[16], name_base[17], name_base[18]);
		prop[3] = median(name_base[19], name_base[20], name_base[21]);
		prop[4] = median(name_base[22], name_base[23], name_base[24]);
		prop[5] = median(name_base[25], name_base[26], name_base[27]);
		prop[6] = median(name_base[28], name_base[29], name_base[30]);
	}
	void calc_skills(const char *name)
	{
		memcpy(val, val_base, sizeof val);
		u16_t s;
		for (int _ = 0; _ < 2; _++)
			for (int i = s = 0; i < N; i++)
			{
				if (i & 15)
					s += name[(i & 15) - 1];
				s += val[i];
				std::swap(val[i], val[s]);
			}
		q_len = -1;
		for (int i = 0; i < N; i++)
			if ((val[i] * 181 + 160 & 255) >= 89 && (val[i] * 181 + 160 & 255) < 217)
				name_base[++q_len] = val[i] * 181 + 160 & 63;
		u16_t *a = name_base + K;
		for (int i = 0; i < skill_cnt; i++)
			skill[i] = i;
		memset(freq, 0, sizeof freq);
		p = q = 0;
		for (int s = 0, _ = 0; _ < 2; _++)
			for (int i = 0; i < skill_cnt; i++)
			{
				s = (s + gen() + skill[i]) % skill_cnt;
				std::swap(skill[i], skill[s]);
			}
		int last = -1;
		for (int i = 0, j = 0; i < K; i += 4, j++)
		{
			u16_t p = std::min({a[i], a[i + 1], a[i + 2], a[i + 3]});
			if (p > 10 && skill[j] < 35)
			{
				freq[j] = p - 10;
				if (skill[j] < 25)
					last = j;
			}
		}
		if (last != -1)
			freq[last] <<= 1;
		if (freq[14] && last != 14)
			freq[14] += std::min({name_base[60], name_base[61], freq[14]});
		if (freq[15] && last != 15)
			freq[15] += std::min({name_base[62], name_base[63], freq[15]});
	}
};
int n, jyztxdy, jyzyyds, tp;
long long l, r;
u16_t idx[16];
Name name;
void read(char *p)
{
	while ((*p = getchar()) == '\n')
		;
	while ((*++p = getchar()) != '\n')
		;
	*p = 0;
}
int main()
{
	puts("输入战队名:");
	read(team);
	std::mt19937_64 rnd(time(0));
	name.load_team(team);
	puts("输入前缀(前缀为空则输入$):");
	read(_tmp);
	char *tmp = cvt(_tmp);
	jyzyyds = jyztxdy = strlen(tmp);
	if (tmp[0] == '$')
		jyzyyds = 0;
	puts("选择测号模式:\n1. 顺序数字和字母\n2. 顺序数字\n3. 顺序大写字母");
	puts("4. 随机数字和大写字母\n5. 随机汉字");
	std::cin >> tp;
	if (jyztxdy > 7 && tp == 1 || jyztxdy > 3 && tp == 2 || jyztxdy > 6 && tp == 3 || jyztxdy > 5 && tp == 4 || (jyzyyds % 3 || jyzyyds > 6) && tp == 5)
	{
		puts("可以换一个更短一点的前缀吗qwq");
		system("pause");
		puts("按回车键返回");
		return 0;
	}
	if (tp <= 0 || tp > 5)
	{
		puts("还没有这种模式哦，快去向曙光催更吧qwq");
		system("pause");
		puts("按回车键返回");
		return 0;
	}
	if (jyzyyds == 6 && tp == 5)
		puts("Tips: 此测号模式很容易重复，请注意及时更换前缀哦");
	if (tp < 4)
	{
		puts("输入区间(l,r]:");
		std::cin >> l >> r;
	}
	else
	{
		puts("输入测号量:");
		std::cin >> r;
		l = 0;
	}
	r*=1e8;
	puts("输出文件:");
	read(fname);
	FILE *fp = fopen(fname, "w");
	if (!fp)
	{
		fputs("文件打开失败", stderr);
		system("pause");
	}
	clock_t start = clock();
	if (tp < 4)
	{
		if (tp != 3)
			for (int i = 14; i >= jyzyyds; i--)
				tmp[i] = '0';
		if (tp == 3)
			for (int i = 14; i >= jyzyyds; i--)
				tmp[i] = 'A';
		u16_t tmpp[15];
		long long l1 = l;
		if (tp == 1)
			for (int i = 14; i >= 0; i--)
				tmpp[i] = l1 % 62, l1 /= 62;
		if (tp == 2)
			for (int i = 14; i >= 0; i--)
				tmpp[i] = l1 % 10, l1 /= 10;
		if (tp == 3)
			for (int i = 14; i >= 0; i--)
				tmpp[i] = l1 % 26, l1 /= 26;
		for (int pos = jyzyyds; pos < 15; pos++)
			for (int _ = 0; _ < tmpp[pos]; _++)
			{
				tmp[pos]++;
				if (tp == 1)
				{
					if (tmp[pos] == '9' + 1)
						tmp[pos] = 'A';
					if (tmp[pos] == 'Z' + 1)
						tmp[pos] = 'a';
				}
			}
	}
	for (u64_t i = l, j = 1, k = 0; i < r; i++, j++)
	{
		if (tp < 4)
		{
			int pos = 14;
			tmp[pos]++;
			if (tp == 1)
			{
				if (tmp[pos] == '9' + 1)
					tmp[pos] = 'A';
				if (tmp[pos] == 'Z' + 1)
					tmp[pos] = 'a';
			}
			while (tp == 1 && tmp[pos] == 'z' + 1 || tp == 2 && tmp[pos] == '9' + 1 || tp == 3 && tmp[pos] == 'Z' + 1)
			{
				tmp[pos] = tp != 3 ? '0' : 'A';
				--pos;
				tmp[pos]++;
				if (tp == 1)
				{
					if (tmp[pos] == '9' + 1)
						tmp[pos] = 'A';
					if (tmp[pos] == 'Z' + 1)
						tmp[pos] = 'a';
				}
			}
		}
		if (tp == 4)
			for (int pos = jyzyyds; pos < 15; pos++)
			{
				tmp[pos] = rnd() % 36;
				if (tmp[pos] < 10)
					tmp[pos] = '0' + tmp[pos];
				else
					tmp[pos] = 'A' + tmp[pos] - 10;
			}
		if (tp == 5)
			for (int pos = jyzyyds; pos < 15; pos += 3)
			{
				bool flag = 0;
				while (!flag)
				{
					tmp[pos] = -23 - rnd() % 6;
					tmp[pos + 1] = -65 - rnd() % 64;
					tmp[pos + 2] = -65 - rnd() % 64;
					if (tmp[pos] < -23 && tmp[pos] > -28)
						flag = 1;
					else if (tmp[pos] == -23 && (tmp[pos + 1] >= -65 || tmp[pos + 2] >= -81))
						flag = 1;
					else if (tmp[pos] == -28 && (tmp[pos + 1] >= -72))
						flag = 1;
				}
			}
		for (int w = 1; w <= 15; w++)
			tmq[w] = tmp[w - 1];
		name.load_name(tmq);
		if (V * 3 >= 1320)
		{ // 三表
			name.calc_skills(tmp);
			for (int j = 0; j < 7; j++)
				prop[j] += 36;
			bool flag = 0, flag2 = 0;
			int sum = V + 36 * 7, sum2 = 0;
			for (int _ = 0; _ < 16; _++)
				sum2 += name.freq[_];
			// sum: 八围 ; sum2: 技能熟练度总和 ; name.freq: 每项技能熟练度
			if (sum >= 712)
				flag = 1; // 八围达到四表标准
			if (prop[4] <= 55 || sum >= 707 && prop[4] <= 60)
				flag = 1; // 魔低号
			if (sum - prop[0] >= 645 && prop[4] >= 85 && prop[6] >= 85)
				flag = 1; // 攻低号, 要求 魔/智 都不能低
			for (int _ = 0; _ < 16; _++)
			{
				if (name.freq[_] >= 80)
					flag = flag2 = 1;	 // 单项技能超高号
				if (name.skill[_] == 21) // 背刺
					if (prop[0] + prop[4] + 10 < prop[1] + prop[5] && name.freq[_] > 50)
						flag = flag2 = 1;
				// 熟练度 > 50 且 攻击属性 < 防御属性
				if (name.skill[_] == 17) // 净化
					if (name.freq[_] > 65)
						flag = flag2 = 1; // 熟练度 > 65
			}
			if (sum2 >= 160)
				flag = 1; // 技能总熟练度 >= 160
			if (sum2 <= 120 && !flag2 && sum <= 722)
				flag = 0; // 去除技能较少且没有单项好技能的低八围号
			if (sum2 <= 100 && !flag2 && sum <= 732)
				flag = 0; // 去除技能很少且没有单项好技能的中低八围号
			if (flag)
			{
				char *tmp_ = dvt(tmp);
				fprintf(fp, "%s@%s\n", tmp_, team);
				fflush(fp);
			}
		}
		if (j == 2e6)
		{
			j -= 2e6;
			k += 2;
			clock_t end = clock();
			double tm = 1.0 * (end - start) / CLOCKS_PER_SEC;
			fprintf(stderr, "count: %lluk, time: %.2fs, speed: %.0fk/d.\n", k * 1000, tm, k * 1e3 / tm * 86400);
		}
	}
	//fputs("测号已完成，按回车键关闭。", stderr);
	system("pause");
	return 0;
}